﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Av.Utils;
using System.Threading;
using System.Reflection;
using System.IO;
using System.Net;

namespace SymcmsSync
{
    public partial class Form1 : Form
    {
        protected NotifyIcon m_icon = null;

        private List<KeyValuePair<string, ProductItem>> m_products = new List<KeyValuePair<string,ProductItem>>();

        delegate void InsertProductToGridDelegate(ProductItem pr);

        delegate void RepaintDelegate(object obj);

        #region " Get/set text methods (invoked) "

        delegate void SetTextDelegate(string name, string value);
        delegate string GetTextDelegate(string name);

        /// <summary>
        /// Returns text of control.
        /// </summary>
        /// <param name="name">Name of control</param>
        /// <returns>Text of control. Returns "checked"/"" or "" for CheckBox</returns>
        private string GetText(string name)
        {
            string s = "";

            try
            {
                if( this.InvokeRequired )
                {
                    this.Invoke(new GetTextDelegate(GetText), name);
                } else
                {
                    Control[] ar = this.Controls.Find(name, false);
                    if( (ar != null) && (ar.Length > 0) )
                    {
                        if( ar[0].GetType() == typeof(CheckBox) )
                        {
                            s = ((CheckBox)ar[0]).Checked ? "checked" : "";
                        } else
                        {
                            s = ar[0].Text;
                        }
                    }
                }
            } catch( Exception ex )
            {
            }

            return s;
        }

        /// <summary>
        /// Thread safe AddText
        /// </summary>
        /// <param name="name">Name of control to add text</param>
        /// <param name="value">Text to add</param>
        private void AddText(string name, string value)
        {
            try
            {
                if( this.InvokeRequired )
                {
                    this.Invoke(new SetTextDelegate(AddText), name, value);
                } else
                {
                    Control[] ar = this.Controls.Find(name, false);
                    if( (ar != null) && (ar.Length > 0) )
                    {
                        ar[0].Text += value + Environment.NewLine;
                        if( ar[0].GetType() == typeof(TextBox) )
                        {
                            ((TextBox)ar[0]).SelectionStart = Int32.MaxValue;
                        }
                    }
                }
            } catch( Exception )
            {
            }
        }

        /// <summary>
        /// Thread safe SetText
        /// </summary>
        /// <param name="name">Name of control to set text</param>
        /// <param name="value">Text to set</param>
        private void SetText(string name, string value)
        {
            try
            {
                if( this.InvokeRequired )
                {
                    this.Invoke(new SetTextDelegate(SetText), name, value);
                } else
                {
                    Control[] ar = this.Controls.Find(name, false);
                    if( (ar != null) && (ar.Length > 0) )
                    {
                        ar[0].Text = value;
                    }
                }

            } catch( Exception ex )
            {
            }
        }

        #endregion

        public Form1()
        {
            Log4cs.dir = Common.GetPath() + "Logs\\";
            Log4cs.outputToConsole = false;
            Log4cs.logName = "symsync_{0}.log";

            InitializeComponent();

            FormatProductGrid();

            //InsertProductToGrid(null);
        }

        protected override void OnLoad(EventArgs e)
        {
            try
            {
                Log4cs.Log("Starting {0} (v{1})...", Settings.Name, Settings.Version);
                InitializeComponent();

                bool createdNew = false;
                Mutex mx = new Mutex(false, "SymcmsSync", out createdNew);
                Log4cs.Log(Importance.Debug, "Is mutex created: {0}", createdNew);

                // If application is already running
                if( createdNew == false )
                {
                    throw new ApplicationException("Application is already running!");
                }


                this.Text = string.Format("{0} (v{1})", Settings.Name, Settings.Version);

                Settings.Load();
                Log4cs.Log(Settings.ToString());

                //m_informer.Add(Settings.TrackerItems[0]);
                //m_informer.ForceInform();


                //Log4cs.Log("Initializing error queue for {0} errors", m_maxErrors);
                //m_errorQ = new Queue(m_maxErrors);

                // Create tray icon
                Assembly asm = Assembly.GetExecutingAssembly();
                FileInfo fi = new FileInfo(asm.GetName().Name);
                using( Stream s = asm.GetManifestResourceStream(string.Format("{0}.av1.ico", fi.Name)) )
                {
                    m_icon = new NotifyIcon();
                    m_icon.Visible = true;
                    m_icon.Icon = new Icon(s);
                }

                // Create context menu for tray icon
                MenuItem[] arMenu = this.CreateMenuItems();
                if( arMenu != null )
                    m_icon.ContextMenu = new ContextMenu(arMenu);

                //m_statusThread = new GetStatusThread();

                //throw new Exception("Test");

                // Assign callback for OK and failed actions
                //m_statusThread.SiteTrackedOk += new SiteIsTrackedDelegate(OnSiteTrackedOk);
                //m_statusThread.SiteTrackedFail += new SiteIsTrackedDelegate(OnSiteTrackedFail);
                //m_statusThread.AllSitesDone += new SiteWholeListDoneDelegate(OnAllSitesChecked);

            } catch( Exception ex )
            {
                Log4cs.Log(Importance.Error, "Error loading main form!");
                Log4cs.Log(Importance.Debug, ex.ToString());
                MessageBox.Show("Error loading application!", string.Format("{0} (v{1})", Settings.Name, Settings.Version), MessageBoxButtons.OK, MessageBoxIcon.Error);
                this.Close();
            }

        }

        private void FormatProductGrid()
        {
            Log(Importance.Debug, "Creating product grid...");
            gridProducts.ColumnsCount = 3;
            gridProducts.FixedRows = 1;
            gridProducts.Rows.Insert(0);
            gridProducts[0, 0] = new SourceGrid.Cells.ColumnHeader("Code");
            gridProducts[0, 1] = new SourceGrid.Cells.ColumnHeader("Price");
            gridProducts[0, 2] = new SourceGrid.Cells.ColumnHeader("Quantity");

            gridProducts.Columns[0].AutoSizeMode = SourceGrid.AutoSizeMode.EnableAutoSize | SourceGrid.AutoSizeMode.EnableStretch;
            gridProducts.Columns[1].AutoSizeMode = SourceGrid.AutoSizeMode.EnableAutoSize;
            gridProducts.Columns[2].AutoSizeMode = SourceGrid.AutoSizeMode.EnableAutoSize;

            InsertProductToGrid(null);

            gridProducts.AutoSizeCells();
        }

        /// <summary>
        /// Creates context menu for tray icon
        /// </summary>
        /// <returns></returns>
        private MenuItem[] CreateMenuItems()
        {
            MenuItem[] arMenu = null;

            try
            {
                // Got quantity of menus
                arMenu = new MenuItem[MyMenu.Size];

                for( int i = 0; i < MyMenu.Size; i++ )
                {
                    arMenu[i] = new MenuItem(MyMenu.ToName(i), OnContextMenuClicked);
                }

                // By default status thread is stopped, so disable "Stop" command
                arMenu[MyMenu.Position.Stop].Enabled = false;

                // Format "Version"
                arMenu[MyMenu.Position.Version].Text = string.Format("{0} (v{1})", Settings.Name, Settings.Version);

            } catch( Exception ex )
            {
                Log4cs.Log(Importance.Error, "Error creating menu items!");
                Log4cs.Log(Importance.Debug, ex.ToString());
            }

            return arMenu;
        }

        void OnContextMenuClicked(object sender, EventArgs e)
        {
            try
            {
                switch( ((MenuItem)sender).Index )
                {
                    case MyMenu.Position.Start:
                        m_icon.ContextMenu.MenuItems[0].Enabled = false;
                        m_icon.ContextMenu.MenuItems[1].Enabled = true;
                        //OnStartStopClicked(null, null);
                        break;
                    case MyMenu.Position.Stop:
                        m_icon.ContextMenu.MenuItems[0].Enabled = true;
                        m_icon.ContextMenu.MenuItems[1].Enabled = false;
                        //OnStartStopClicked(null, null);
                        break;
                    case MyMenu.Position.Version:
                        MessageBox.Show("Site Status Tracker by mr. Aleksej Vasinov", Settings.NameVersion, MessageBoxButtons.OK, MessageBoxIcon.Information);
                        break;
                    case MyMenu.Position.Reload:
                        //ReloadSettings();
                        break;
                    case MyMenu.Position.LastErrors:
                        //if( m_errorQ.Count > 0 )
                        //{
                        //    Log4cs.Log("Showing last errors...");
                        //    object[] obj = m_errorQ.ToArray();
                        //    StringBuilder sb = new StringBuilder();
                        //    foreach( ErrorItem err in obj )
                        //    {
                        //        sb.AppendFormat("{0} {1}{2}", err.ErrorTime.ToString("HH:mm:ss"), err.TaskName, Environment.NewLine);
                        //    }
                        //    MessageBox.Show(sb.ToString(), Settings.Name, MessageBoxButtons.OK, MessageBoxIcon.Information);

                        //} else
                        //    Log4cs.Log(Importance.Warning, "No errors to show!");
                        break;
                    default:
                        this.Close();
                        break;
                }

            } catch( Exception ex )
            {
                Log4cs.Log(Importance.Error, "Error handling context menu click!");
                Log4cs.Log(Importance.Debug, ex.ToString());
            }
        }
        private void OnFormClosing(object sender, FormClosingEventArgs e)
        {
            Log4cs.Log("Main form is closing...");
            if( m_icon != null )
                m_icon.Dispose();

            //if( m_statusThread != null )
            //{
            //    m_statusThread.Stop();
            //}
        }

        private void OnLoadButtonClicked(object sender, EventArgs e)
        {
            try
            {
                OpenFileDialog dlg = new OpenFileDialog();
                if( dlg.ShowDialog() == DialogResult.OK )
                {
                    string filename = dlg.FileName;
                    if( filename.ToLower().EndsWith(".csv") )
                    {
                        Log("Processing file: {0}...", filename);
                        List<ProductItem> arProducts = new List<ProductItem>();
                        string[] arLines = File.ReadAllLines(filename);


                        for( int i = 0; i < arLines.Length; i++ )
                        {
                            ProductItem pr = ParceCsvProductLine(arLines[i]);
                            if( pr != null )
                            {
                                arProducts.Add(pr);
                                m_products.Add(new KeyValuePair<string,ProductItem>(pr.Code, pr));
                            }
                        }

                    } else
                    {
                        Log(Importance.Warning, "Not a CSV file: {0}", filename);
                    }
                }

                RepaintGrid(null);
                InsertProductToGrid(null);
            } catch( Exception ex )
            {
                Log(Importance.Error, "Error processing CSV file!");
                Log(Importance.Debug, ex.ToString());
            }
        }

        private void RepaintGrid(object obj)
        {
        }

        private void InsertProductToGrid(ProductItem pr)
        {
            if( this.InvokeRequired )
            {
                this.Invoke(new InsertProductToGridDelegate(InsertProductToGrid), pr);
            } else
            {
                Log("Inserting 1 row to grid..");
                int r = gridProducts.RowsCount;
                Log("Grid has {0} rows...", r);
                //r += 1;
                gridProducts.Rows.Insert(r);
                gridProducts[r, 0] = new SourceGrid.Cells.Cell(" ");
                gridProducts[r, 1] = new SourceGrid.Cells.Cell(" ");
                gridProducts[r, 2] = new SourceGrid.Cells.Cell(" ");
            }

        }

        private ProductItem ParceCsvProductLine(string p)
        {
            ProductItem pr = null;

            Log(Importance.Debug, "Splitting line: {0}", p);
            string[] ar = p.Split(new char[] { '"' });
            //Log(Importance.Debug, "Got {0} pieces", ar.Length);

            if( ar.Length == 7 )
            {
                pr = new ProductItem();
                pr.Code = ar[1];
                pr.Quantity = Int32.Parse(ar[3]);
                pr.Price = float.Parse(ar[5]);
            } else
            {
                Log(Importance.Error, "Bad string!");
            }

            return pr;
        }

        private void OnUploadButtonClicked(object sender, EventArgs e)
        {
            WebClient wc = new WebClient();
            foreach( KeyValuePair<string, ProductItem> kvp in m_products )
	        {
                string rqUrl = string.Format("http://eshop.interateitis.lt/index.php/pradmin/sync/code/{0}/price/{1}/qnt/{2}", kvp.Key, kvp.Value.Price, kvp.Value.Quantity);
                Log("Syncing product: {0}...", rqUrl);
                byte[] ba = wc.DownloadData(rqUrl);
                if( ba != null )
                {
                    string s = Encoding.UTF8.GetString(ba);
                    Log("Response from server: {0}", s.StartsWith("2") ? "OK" : "FAILED");
                }
	        }
        }


        protected void Log(string msg, params object[] args)
        {
            Log(Importance.Info, msg, args);
        }

        protected void Log(Importance logLevel, string msg, params object[] args)
        {
            this.AddText("txtOutput", string.Format(msg, args));
            Log4cs.Log(logLevel, msg, args);
        }

        private void OnGetFromButtonClicked(object sender, EventArgs e)
        {
            string url = "";

            url = "http://eshop.interateitis.lt/test.php/pradmin/quantityexport";
            Log("Sending request to prepare CSV file [{0}]...", url);
            WebClient wc = new WebClient();
            wc.UploadData(url, "POST", new byte[] { 0x01 });
            Log("File is prepared");

            Log("Downloading CSV file...");
            string file = DateTime.Now.ToString("yyyy-MM-dd");
            url = "http://eshop.interateitis.lt/test.php/pradmin/get/file/" + file;
            wc.DownloadFile(url, "C:\\temp\\" + file + ".csv");
            Log("Downloaded");
        }


    }
}
